package org.dht.com.tra.nw;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;
import org.dht.com.msg.MalformedMessageException;
import org.dht.com.msg.Message;
import org.dht.com.msg.MessageXML;
import org.dht.com.tra.Communicator;

/**
 * The <code>UnicastManagerTCP</code> class implemented transfer message based
 * in TCP
 * 
 */
public class UnicastManagerTCP implements Communicator {

	/**
	 * Logger
	 */
	private static final Logger logger = Logger
			.getLogger(UnicastManagerTCP.class);

	/**
	 * The server socket that will be waiting for connection.
	 */
	private ServerSocket serverSocket;

	/**
	 * The value of the port used to create the socket.
	 */
	private int portTcp;

	/**
	 * Builds a UnicastManagerTCP
	 * 
	 * @param portTcp
	 *            Port TCP number
	 */
	public UnicastManagerTCP(int portTcp) {
		this.portTcp = portTcp;

		try {
			this.serverSocket = new ServerSocket(portTcp);
		} catch (IOException e) {
			logger.error("Error creating server socket", e);
		}
	}

	/*
	 * (non-Javadoc)
	 */
	public Message reciever() {
		Socket socket = null;
		String stringMessage;
		Message message = null;
		ObjectInputStream objectInputStream;

		try {
			socket = serverSocket.accept();

			objectInputStream = new ObjectInputStream(socket.getInputStream());
			stringMessage = (String) objectInputStream.readObject();

			message = MessageXML.valueOf(stringMessage);

		} catch (IOException e) {
			logger.error("Error reading socket", e);
		} catch (ClassNotFoundException e) {
			logger.error("Error reading socket", e);
		} catch (MalformedMessageException e) {
			logger.error("Error reading message", e);
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				logger.error("Error closed socket", e);
			}
		}

		return message;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * co.edu.uniquindio.utils.communication.transfer.Communicator#send(co.edu
	 * .uniquindio.utils.communication.message.Message)
	 */
	public void send(Message message) {

		Socket socket = null;
		try {
			socket = new Socket(message.getMessageDestination(), portTcp);

			ObjectOutputStream objectOutputStream = new ObjectOutputStream(
					socket.getOutputStream());
			objectOutputStream.writeObject(message.toString());
			objectOutputStream.flush();

		} catch (UnknownHostException e) {
			logger.error("Error writting socket", e);
		} catch (IOException e) {
			logger.error("Error writting socket", e);
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				logger.error("Error closed socket", e);
			}
		}

	}

	/**
	 * Gets port TCP
	 * 
	 * @return Port TCP
	 */
	public int getPortTcp() {
		return portTcp;
	}

	/**
	 * Sets port TCP
	 * 
	 * @param portTcp
	 *            Port TCP
	 */
	public void setPortTcp(int portTcp) {
		this.portTcp = portTcp;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see co.edu.uniquindio.utils.communication.transfer.Stoppable#stop()
	 */
	public void stop() {
		try {
			serverSocket.close();
		} catch (IOException e) {
			logger.error("Error closed server socket", e);
		}
	}

}
